package com.hunliji.monitor.web.facade.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hunliji.common.exception.WarnException;
import com.hunliji.common.utils.SnowflakeIdUtil;
import com.hunliji.monitor.dao.mapper.bd.StoreMapper;
import com.hunliji.monitor.dao.mapper.wallet.MerchantWalletAccountMapper;
import com.hunliji.monitor.dao.mapper.wallet.MerchantWalletFlowDetailMapper;
import com.hunliji.monitor.dao.mapper.wallet.MerchantWalletFlowMapper;
import com.hunliji.monitor.dao.mapper.wallet.MerchantWalletMapper;
import com.hunliji.monitor.dao.mapper.wedding.MerchantBondBalanceMapper;
import com.hunliji.monitor.dao.mapper.wedding.MerchantsMapper;
import com.hunliji.monitor.dao.model.dataobject.*;
import com.hunliji.monitor.web.facade.DataSyncFacade;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DataSyncFacadeImpl implements DataSyncFacade {

    private static List<Long> hasErrorMerchantIdList =  new ArrayList<>();
    @Resource
    private MerchantsMapper merchantsMapper;
    @Resource
    private MerchantWalletMapper merchantWalletMapper;
    @Resource
    private MerchantWalletAccountMapper merchantWalletAccountMapper;
    @Resource
    private MerchantBondBalanceMapper merchantBondBalanceMapper;
    @Resource
    private MerchantWalletFlowMapper merchantWalletFlowMapper;
    @Resource
    private MerchantWalletFlowDetailMapper merchantWalletFlowDetailMapper;
    @Resource
    private StoreMapper storeMapper;
    @Override
    @Transactional(rollbackFor = {Exception.class,RuntimeException.class},transactionManager = "walletTransactionManager")
    public void syncBond(List<Long> merchantIdList) {
        hasErrorMerchantIdList = new ArrayList<>();
//        if(CollectionUtils.isEmpty(merchantIdList)){
//            throw new WarnException("当前阶段商家id必传");
//        }
        try {
            if(CollectionUtils.isEmpty(merchantIdList)){
                log.info("无商家id传入，通过查询获取");
                Long id = 0L;
                for (int i = 1;i<1000;i++){
                    log.info("第{}次执行查询",i);
                    LambdaQueryWrapper<MerchantsDO> merchantQueryWrapper = new LambdaQueryWrapper<MerchantsDO>();
                    merchantQueryWrapper.eq(MerchantsDO::getDeleted,Boolean.FALSE);
                    merchantQueryWrapper.gt(MerchantsDO::getId,id);
                    merchantQueryWrapper.gt(MerchantsDO::getBondFee,new BigDecimal("0"));
                    merchantQueryWrapper.orderBy(true,true,MerchantsDO::getId);
                    PageHelper.startPage(1,50);
                    List<MerchantsDO> merchantsDOList = merchantsMapper.selectList(merchantQueryWrapper);;
                    if(i == 1){
                        PageInfo<MerchantsDO> pageInfo = new PageInfo<>(merchantsDOList);
                        log.info("总共需要处理的数据数量为num:{}",pageInfo.getTotal());
                    }
                    if(CollectionUtils.isEmpty(merchantsDOList)){
                        log.info("查询结束");
                        break;
                    }
                    id = (merchantsDOList.get(merchantsDOList.size()-1)).getId();
                    doSyncHasData(merchantsDOList,i);

                }
            }else {
                List<List<Long>> partitionList = ListUtils.partition(merchantIdList,50);
                for (List<Long> partition:partitionList){
                    doSync(partition);
                }
            }
        }finally {
            log.warn("本次处理结束，存在错误商家id集合:{}",JSON.toJSONString(hasErrorMerchantIdList));
        }
    }

    @Override
    public void syncRecord() {
        Long id = 0L;
        for (int i = 1;i<1000;i++) {
            //迁移钱包流水
            LambdaQueryWrapper<MerchantBondBalanceDO> bondBalanceQueryWrapper = new LambdaQueryWrapper<MerchantBondBalanceDO>();
            bondBalanceQueryWrapper.gt(MerchantBondBalanceDO::getId, id);
            bondBalanceQueryWrapper.orderBy(true, true, MerchantBondBalanceDO::getId);
            PageHelper.startPage(1, 50);
            List<MerchantBondBalanceDO> bondBalanceDOList = merchantBondBalanceMapper.selectList(bondBalanceQueryWrapper);
            if(CollectionUtils.isEmpty(bondBalanceDOList)){
                log.warn("查询结束");
                break;
            }
            id = (bondBalanceDOList.get(bondBalanceDOList.size()-1)).getId();
            //获取里面有哪些钱包账户，并且进行查询
            List<Integer> merchantIdList = bondBalanceDOList.stream().map(MerchantBondBalanceDO::getMerchantId).collect(Collectors.toList());
            LambdaQueryWrapper<MerchantWalletDO> walletQueryWrapper = new LambdaQueryWrapper<MerchantWalletDO>();
            walletQueryWrapper.in(MerchantWalletDO::getMerchantId,merchantIdList);
            walletQueryWrapper.eq(MerchantWalletDO::getDeleted,Boolean.FALSE);
            List<MerchantWalletDO> walletDOList = merchantWalletMapper.selectList(walletQueryWrapper);
            List<Long> walletIdList = walletDOList.stream().map(MerchantWalletDO::getId).collect(Collectors.toList());

            LambdaQueryWrapper<MerchantWalletAccountDO> accountQueryWrapper = new LambdaQueryWrapper<MerchantWalletAccountDO>();
            accountQueryWrapper.in(MerchantWalletAccountDO::getMerchantWalletId,walletIdList);
            accountQueryWrapper.eq(MerchantWalletAccountDO::getDeleted,Boolean.FALSE);
            List<MerchantWalletAccountDO> accountDOList = merchantWalletAccountMapper.selectList(accountQueryWrapper);
            Map<Long,MerchantWalletAccountDO> accountDOMap = accountDOList.stream().collect(Collectors.toMap(MerchantWalletAccountDO::getMerchantWalletId,account->account,(a1,a2)->a1));
            Map<Long,MerchantWalletDO> walletDOMap = walletDOList.stream().collect(Collectors.toMap(MerchantWalletDO::getMerchantId,wallet->wallet,(w1,w2)->w2));


            for (MerchantBondBalanceDO bondBalanceDO:bondBalanceDOList){
                MerchantWalletDO merchantWalletDO = walletDOMap.get(bondBalanceDO.getMerchantId());
                if(Objects.isNull(merchantWalletDO)){
                    log.warn("记录迁移，无法查询到钱包，跳过本记录操作，bondBalanceDO:{}",bondBalanceDO);
                    continue;
                }
                MerchantWalletAccountDO accountDO = accountDOMap.get(merchantWalletDO.getId());
                if(Objects.isNull(accountDO)){
                    log.warn("记录迁移，无法查询到账户，跳过本记录操作，bondBalanceDO:{}",bondBalanceDO);
                    continue;
                }

                //先查询这个流水是否已经进行了迁移
                LambdaQueryWrapper<MerchantWalletFlowDO> flowQueryWrapper = new LambdaQueryWrapper<MerchantWalletFlowDO>();
                flowQueryWrapper.eq(MerchantWalletFlowDO::getMerchantWalletId, merchantWalletDO.getId());
                flowQueryWrapper.eq(MerchantWalletFlowDO::getTradeSource,bondBalanceDO.getId().toString());
                MerchantWalletFlowDO merchantWalletFlowDO = merchantWalletFlowMapper.selectOne(flowQueryWrapper);
                if(Objects.nonNull(merchantWalletFlowDO)){
                    log.warn("记录迁移，账单已经迁移，bondBalanceDO：{}",JSON.toJSONString(bondBalanceDO));
                    continue;
                }

                MerchantWalletFlowDO flowDO = new MerchantWalletFlowDO();
                flowDO.setTradeNo(String.valueOf(SnowflakeIdUtil.getNextId()));
                flowDO.setMerchantWalletId(merchantWalletDO.getId());
                if(bondBalanceDO.getType() == 1){
                    flowDO.setTradeType(501);
                }
                if(bondBalanceDO.getType() == 2){
                    flowDO.setTradeType(502);
                }
                if(bondBalanceDO.getType() == 3){
                    flowDO.setTradeType(503);
                }
                if(bondBalanceDO.getType() == 3 && "商家保证金退款".equals(bondBalanceDO.getMessage())){
                    flowDO.setTradeType(509);
                }
                if(bondBalanceDO.getType() == 4){
                    flowDO.setTradeType(504);
                }
                if(bondBalanceDO.getType() == 5){
                    flowDO.setTradeType(505);
                }
                if(bondBalanceDO.getType() == 6){
                    flowDO.setTradeType(506);
                }
                flowDO.setTradeSource(bondBalanceDO.getId().toString());
                if(bondBalanceDO.getValue().multiply(new BigDecimal("100")).longValue()<0){
                    flowDO.setFlowType(2);
                    flowDO.setFlowNo(initFlowNo(2,bondBalanceDO.getCreatedAt()));
                }else {
                    flowDO.setFlowType(1);
                    flowDO.setFlowNo(initFlowNo(1,bondBalanceDO.getCreatedAt()));
                }
                flowDO.setTransAmount(bondBalanceDO.getValue().multiply(new BigDecimal("100")).longValue());
                flowDO.setRemark("奖励金迁移");
                flowDO.setDbCreateAt(bondBalanceDO.getCreatedAt());
                flowDO.setDbUpdatedAt(bondBalanceDO.getCreatedAt());
                merchantWalletFlowMapper.insert(flowDO);

                //插入账户明细
                MerchantWalletFlowDetailDO flowDetailDO = new MerchantWalletFlowDetailDO();
                flowDetailDO.setMerchantWalletFlowId(flowDO.getId());
                flowDetailDO.setMerchantWalletAccountId(accountDO.getId());
                if(bondBalanceDO.getValue().multiply(new BigDecimal("100")).longValue()<0){
                    flowDetailDO.setFlowType(2);
                }else {
                    flowDetailDO.setFlowType(1);
                }
                flowDetailDO.setDbCreateAt(bondBalanceDO.getCreatedAt());
                flowDetailDO.setDbUpdatedAt(bondBalanceDO.getCreatedAt());
                flowDetailDO.setTransAmount(bondBalanceDO.getValue().multiply(new BigDecimal("100")).longValue());
                merchantWalletFlowDetailMapper.insert(flowDetailDO);

                log.warn("单条记录迁移完成，bondBalanceDO:{}",bondBalanceDO);
            }
        }






    }

    @Override
    public void syncBondCheck() {
        //查询老账户中，大于0的记录，这些是第一要确保被迁移的
        LambdaQueryWrapper<MerchantsDO> merchantQueryWrapper = new LambdaQueryWrapper<MerchantsDO>();
        merchantQueryWrapper.eq(MerchantsDO::getDeleted,Boolean.FALSE);
        merchantQueryWrapper.gt(MerchantsDO::getBondFee,0);
        merchantQueryWrapper.select(MerchantsDO::getId);
        List<MerchantsDO> merchantsDOList = merchantsMapper.selectList(merchantQueryWrapper);
        List<Long> oldMerchantIdList = merchantsDOList.stream().map(MerchantsDO::getId).collect(Collectors.toList());

        //查询新账户
        LambdaQueryWrapper<MerchantWalletAccountDO> merchantWalletAccountQueryWrapper = new LambdaQueryWrapper<MerchantWalletAccountDO>();
        merchantWalletAccountQueryWrapper.eq(MerchantWalletAccountDO::getAccountType,3);
        merchantWalletAccountQueryWrapper.eq(MerchantWalletAccountDO::getDeleted,Boolean.FALSE);
        merchantWalletAccountQueryWrapper.select(MerchantWalletAccountDO::getId,MerchantWalletAccountDO::getMerchantWalletId);
        List<MerchantWalletAccountDO> accountDOList = merchantWalletAccountMapper.selectList(merchantWalletAccountQueryWrapper);
        List<Long> walletIdList = accountDOList.stream().map(MerchantWalletAccountDO::getMerchantWalletId).collect(Collectors.toList());

        LambdaQueryWrapper<MerchantWalletDO> walletDOLambdaQueryWrapper = new LambdaQueryWrapper<MerchantWalletDO>();
        walletDOLambdaQueryWrapper.in(MerchantWalletDO::getId,walletIdList);
        walletDOLambdaQueryWrapper.eq(MerchantWalletDO::getDeleted,Boolean.FALSE);
        walletDOLambdaQueryWrapper.select(MerchantWalletDO::getId,MerchantWalletDO::getMerchantId);
        List<MerchantWalletDO> walletDOList = merchantWalletMapper.selectList(walletDOLambdaQueryWrapper);
        List<Long> newMerchantIdList = walletDOList.stream().map(MerchantWalletDO::getMerchantId).collect(Collectors.toList());

        oldMerchantIdList.removeAll(newMerchantIdList);
        if(CollectionUtils.isEmpty(oldMerchantIdList)){
            log.warn("迁移成功");
        }else {
            log.warn("迁移存在问题,存在问题的商家size:{}：data:{}",oldMerchantIdList.size(),JSON.toJSONString(oldMerchantIdList));
        }
        //查询明细
    }

    private void doSync(List<Long> merchantIdList){
        if(CollectionUtils.isEmpty(merchantIdList)){
            return;
        }
        //先根据id查询
        LambdaQueryWrapper<MerchantsDO> merchantQueryWrapper = new LambdaQueryWrapper<MerchantsDO>();
        merchantQueryWrapper.in(MerchantsDO::getId,merchantIdList);
        merchantQueryWrapper.eq(MerchantsDO::getDeleted,Boolean.FALSE);
        List<MerchantsDO> merchantsDOList = merchantsMapper.selectList(merchantQueryWrapper);
        log.info("查询到到数据,merchantsDOList:{}",JSON.toJSONString(merchantsDOList));

        doSyncHasData(merchantsDOList,1);

    }

    private void doSyncHasData(List<MerchantsDO> merchantsDOList,Integer i){
        if(CollectionUtils.isEmpty(merchantsDOList)){
            return;
        }
        log.info("查询到到数据,merchantsDOList:{}",JSON.toJSONString(merchantsDOList));
        List<Long> merchantIdList = merchantsDOList.stream().filter(item-> Objects.nonNull(item.getBondFee()) && item.getBondFee().longValue()>0).map(MerchantsDO::getId).collect(Collectors.toList());
        log.info("原始数据数量:{},需要处理数据数量:{}",merchantsDOList.size(),merchantIdList.size());
        if(CollectionUtils.isEmpty(merchantIdList)){
            return;
        }
        LambdaQueryWrapper<StoreDO> storeDOQueryWrapper = new LambdaQueryWrapper<StoreDO>();
        storeDOQueryWrapper.in(StoreDO::getMerchantId,merchantIdList);
        storeDOQueryWrapper.eq(StoreDO::getDeleted,Boolean.FALSE);
        List<StoreDO> storeDOList = storeMapper.selectList(storeDOQueryWrapper);
        Map<Long,Long> merchantAndCorpMap = storeDOList.stream().collect(Collectors.toMap(StoreDO::getMerchantId,StoreDO::getCorpId,(v1,v2)->v1));
        int j=1;
        for (MerchantsDO merchantsDO:merchantsDOList){
            try {
                if(Objects.nonNull(merchantsDO.getBondFee()) && merchantsDO.getBondFee().longValue()>0){
                    log.info("处理第{}批，第{}个",i,j);
                    Long corpId = merchantAndCorpMap.get(merchantsDO.getId());
                    if(Objects.isNull(corpId)){
                        log.warn("查询的店铺不存在企业，跳过处理，merchantsDO：{}",JSON.toJSONString(merchantsDO));
                        j++;
                        continue;
                    }
                    //查询钱包是否存在
                    LambdaQueryWrapper<MerchantWalletDO> merchantWalletQueryWrapper = new LambdaQueryWrapper<MerchantWalletDO>();
                    merchantWalletQueryWrapper.eq(MerchantWalletDO::getCorpId,corpId);
                    merchantWalletQueryWrapper.eq(MerchantWalletDO::getMerchantId,merchantsDO.getId());
                    merchantWalletQueryWrapper.eq(MerchantWalletDO::getWalletType,1);
                    merchantWalletQueryWrapper.eq(MerchantWalletDO::getDeleted,Boolean.FALSE);
                    MerchantWalletDO merchantWalletDO = merchantWalletMapper.selectOne(merchantWalletQueryWrapper);
                    if(Objects.nonNull(merchantWalletDO)){
                        log.warn("钱包已存在，跳过处理，merchantsDO：{}",JSON.toJSONString(merchantsDO));
                    }else {
                        merchantWalletDO = new MerchantWalletDO();
                        merchantWalletDO.setCorpId(corpId);
                        merchantWalletDO.setMerchantId(merchantsDO.getId());
                        merchantWalletDO.setWalletType(1);
                        merchantWalletMapper.insert(merchantWalletDO);
                        log.info("钱包即将被创建，{}",JSON.toJSONString(merchantWalletDO));
                    }

                    //处理账号
                    //查询账户是否存在
                    LambdaQueryWrapper<MerchantWalletAccountDO> merchantWalletAccountQueryWrapper = new LambdaQueryWrapper<MerchantWalletAccountDO>();
                    merchantWalletAccountQueryWrapper.eq(MerchantWalletAccountDO::getMerchantWalletId,merchantWalletDO.getId());
                    merchantWalletAccountQueryWrapper.eq(MerchantWalletAccountDO::getAccountType,3);
                    merchantWalletAccountQueryWrapper.eq(MerchantWalletAccountDO::getDeleted,Boolean.FALSE);
                    MerchantWalletAccountDO accountDO = merchantWalletAccountMapper.selectOne(merchantWalletAccountQueryWrapper);

                    if(Objects.nonNull(accountDO)){
                        //账户已存在，则说明已经迁移
                        log.warn("账户已存在，跳过处理，merchantsDO：{}",JSON.toJSONString(merchantsDO));
                        j++;
                        continue;
                    }
                    accountDO = new MerchantWalletAccountDO();
                    accountDO.setMerchantWalletId(merchantWalletDO.getId());
                    accountDO.setAccountType(3);
                    accountDO.setAmount(merchantsDO.getBondFee().multiply(new BigDecimal("100")).longValue());
                    log.info("账户即将被创建，{}",JSON.toJSONString(accountDO));
                    merchantWalletAccountMapper.insert(accountDO);


                    //迁移钱包流水
                    LambdaQueryWrapper<MerchantBondBalanceDO> bondBalanceQueryWrapper = new LambdaQueryWrapper<MerchantBondBalanceDO>();
                    bondBalanceQueryWrapper.eq(MerchantBondBalanceDO::getMerchantId,merchantsDO.getId());
                    List<MerchantBondBalanceDO> bondBalanceDOList = merchantBondBalanceMapper.selectList(bondBalanceQueryWrapper);
                    if(CollectionUtils.isEmpty(bondBalanceDOList)){
                        log.warn("不存在账单记录，跳过处理，merchantsDO：{}",JSON.toJSONString(merchantsDO));
                        j++;
                        continue;
                    }

                    for (MerchantBondBalanceDO bondBalanceDO:bondBalanceDOList){
                        //先查询这个流水是否已经进行了迁移
                        LambdaQueryWrapper<MerchantWalletFlowDO> flowQueryWrapper = new LambdaQueryWrapper<MerchantWalletFlowDO>();
                        flowQueryWrapper.eq(MerchantWalletFlowDO::getMerchantWalletId, merchantWalletDO.getId());
                        flowQueryWrapper.eq(MerchantWalletFlowDO::getTradeSource,bondBalanceDO.getId().toString());
                        MerchantWalletFlowDO merchantWalletFlowDO = merchantWalletFlowMapper.selectOne(flowQueryWrapper);
                        if(Objects.nonNull(merchantWalletFlowDO)){
                            log.warn("账单已经迁移，bondBalanceDO：{}",JSON.toJSONString(bondBalanceDO));
                            continue;
                        }

                        MerchantWalletFlowDO flowDO = new MerchantWalletFlowDO();
                        flowDO.setTradeNo(String.valueOf(SnowflakeIdUtil.getNextId()));
                        flowDO.setMerchantWalletId(merchantWalletDO.getId());
                        if(bondBalanceDO.getType() == 1){
                            flowDO.setTradeType(501);
                        }
                        if(bondBalanceDO.getType() == 2){
                            flowDO.setTradeType(502);
                        }
                        if(bondBalanceDO.getType() == 3){
                            flowDO.setTradeType(503);
                        }
                        if(bondBalanceDO.getType() == 3 && "商家保证金退款".equals(bondBalanceDO.getMessage())){
                            flowDO.setTradeType(509);
                        }
                        if(bondBalanceDO.getType() == 4){
                            flowDO.setTradeType(504);
                        }
                        if(bondBalanceDO.getType() == 5){
                            flowDO.setTradeType(505);
                        }
                        if(bondBalanceDO.getType() == 6){
                            flowDO.setTradeType(506);
                        }
                        flowDO.setTradeSource(bondBalanceDO.getId().toString());
                        if(bondBalanceDO.getValue().multiply(new BigDecimal("100")).longValue()<0){
                            flowDO.setFlowType(2);
                            flowDO.setFlowNo(initFlowNo(2,bondBalanceDO.getCreatedAt()));
                        }else {
                            flowDO.setFlowType(1);
                            flowDO.setFlowNo(initFlowNo(1,bondBalanceDO.getCreatedAt()));
                        }
                        flowDO.setTransAmount(bondBalanceDO.getValue().multiply(new BigDecimal("100")).longValue());
                        flowDO.setRemark("奖励金迁移");
                        flowDO.setDbCreateAt(bondBalanceDO.getCreatedAt());
                        flowDO.setDbUpdatedAt(bondBalanceDO.getCreatedAt());
                        merchantWalletFlowMapper.insert(flowDO);

                        //插入账户明细
                        MerchantWalletFlowDetailDO flowDetailDO = new MerchantWalletFlowDetailDO();
                        flowDetailDO.setMerchantWalletFlowId(flowDO.getId());
                        flowDetailDO.setMerchantWalletAccountId(accountDO.getId());
                        if(bondBalanceDO.getValue().multiply(new BigDecimal("100")).longValue()<0){
                            flowDetailDO.setFlowType(2);
                        }else {
                            flowDetailDO.setFlowType(1);
                        }
                        flowDetailDO.setDbCreateAt(bondBalanceDO.getCreatedAt());
                        flowDetailDO.setDbUpdatedAt(bondBalanceDO.getCreatedAt());
                        flowDetailDO.setTransAmount(bondBalanceDO.getValue().multiply(new BigDecimal("100")).longValue());
                        merchantWalletFlowDetailMapper.insert(flowDetailDO);
                    }
                    j++;
                }
            }catch (Exception e){
                hasErrorMerchantIdList.add(merchantsDO.getId());
            }

        }

    }

    private void createWallet(Long merchantId){

    }

    public static String initFlowNo(Integer flowType, LocalDateTime time) {
        return flowType.toString()
                + DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(time)
                + String.format("%02d",new Random().nextInt(99));
    }
}
